package freejim.icu.highschoolhealthstatuspost.config;


import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import freejim.icu.highschoolhealthstatuspost.util.GetHttpClient;
import org.apache.http.HttpResponse;
import org.apache.http.ParseException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.util.EntityUtils;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AbstractAuthenticationToken;
import org.springframework.security.authentication.AuthenticationDetailsSource;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.ProviderManager;
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.web.DefaultRedirectStrategy;
import org.springframework.security.web.WebAttributes;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

@Configuration
@EnableWebSecurity
public class JLoginConfigurer <H extends HttpSecurityBuilder<H>> extends
        AbstractHttpConfigurer<JLoginConfigurer<H>, H> {
    @Override
    public void configure(H http) {
        http.addFilterAfter(new JLoginConfigurer.JAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
    }

    static class JAuthenticationFilter extends OncePerRequestFilter {

        private static final ProviderManager providerManager = new ProviderManager(Collections.singletonList(new JAuthenticationProvider()));
        @Override
        protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
            if (!request.getRequestURI().endsWith("/login/dgut")) {
                filterChain.doFilter(request, response);
                return;
            }
            JAuthenticationToken authenticationToken = new JAuthenticationToken(request);
            Authentication successAuthentication;
            try {
                successAuthentication = providerManager.authenticate(authenticationToken);
            } catch (AuthenticationException e) {
                // 如果校验失败providerManager会抛异常，在catch里作异常处理。
                response.getWriter().println("auth fail");
                return;
            }
            SecurityContextHolder.getContext().setAuthentication(successAuthentication);
            // 这是认证成功后的sessionID
            try{
                //request.changeSessionId();
            }
            catch (Exception e){
                response.getWriter().println("no sessionid");
                return;
            }
            // 移除之前认证时的错误信息
            request.getSession().removeAttribute(WebAttributes.AUTHENTICATION_EXCEPTION);
            // 成功登录后，设置重定向到页面
            String token = request.getParameter("token");
            Map <String,String> userInfo = postToken(token,"172.27.15.28");
            String userid = userInfo.get("username");
            System.out.println(userid);
            redirectStrategy(request,response,userid);
        }
        // 设置应用系统的AppID，每个应用都不同，你要先去申请注册
        private static String appId = "javaee";

        // 设置应用系统的appSecret，每个应用都不同，你要先去申请注册
        private static String appSecret = "b3b52e43ccfd";
        private static String userInfoService = "https://cas.dgut.edu.cn/oauth/getUserInfo";
        // '中央认证兑票页
        private static String httpService = "https://cas.dgut.edu.cn/ssoapi/v2/checkToken";

        private Map<String, String> postToken(String token, String useip) throws ParseException, IOException {
            String myToken = token;
            String url = httpService;
            Map<String, String> userInfo  =   new HashMap<String,String>();
            //HttpClient httpClient = new DefaultHttpClient();
            HttpClient httpClient = GetHttpClient.getHttpClient();
            String json = jsonMethod(token, useip, appId, appSecret);
            HttpPost post = new HttpPost(url);
            StringEntity postingString = new StringEntity(json);// json传递
            post.setEntity(postingString);
            post.setHeader("Content-type", "application/json");
            HttpResponse response = httpClient.execute(post);
            String content = EntityUtils.toString(response.getEntity());
            if(content != null || "".equals(content)){
                Map<String, String> map = JSON.parseObject(content, Map.class);
                String openid = map.get("openid");
                String accessToken = map.get("access_token");
                if(openid != null || "".equals(openid)){
                    userInfo = getUserInfo(accessToken,openid);
                    System.out.println("userInfo=="+userInfo);
                }
            }
            post.releaseConnection();
            System.out.println("postToken=="+content);
            return userInfo;

        }
        public static String jsonMethod(String token, String userip, String appid, String appsecret) {
            System.out.println("userip==" + userip);
            String localIp = "";
            // 当在服务器上本地测试时，用户访问ip会变成10.0.2.2，而中央认证将获取到本地服务器ip，故需要手动替换
            if ("10.0.2.2".equals(userip)) {
                localIp = "172.27.15.28";
            } else {
                localIp = userip;
            }
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("token", token);
            jsonObject.put("appid", appid);
            jsonObject.put("appsecret", appsecret);
            jsonObject.put("userip", localIp);
            String jsonstr = JSONObject.toJSONString(jsonObject);
            System.out.println("jsonMethod的jsonstr+++++====" + jsonstr);
            return jsonstr;
        }
        private Map<String, String> getUserInfo(String accessToken, String openid) throws ParseException, IOException {
            Map<String, String> infoMap = new HashMap<String,String>();
            //HttpClient httpClient = new DefaultHttpClient();
            HttpClient httpClient = GetHttpClient.getHttpClient();
            HttpPost post = new HttpPost(userInfoService);
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("access_token", accessToken);
            jsonObject.put("openid", openid);
            String jsonstr = JSONObject.toJSONString(jsonObject);
            StringEntity postingString = new StringEntity(jsonstr);// jsonstr传递
            post.setEntity(postingString);
            post.setHeader("Content-type", "application/json");
            HttpResponse response = httpClient.execute(post);
            String content = EntityUtils.toString(response.getEntity());
            System.out.println("getUserInfocontent=="+content);
            if(content != null || "".equals(content)){
                ////获取用户信息
                Map<String, String> map = JSON.parseObject(content, Map.class);
                String username = map.get("username");
                String name = map.get("name");
                String group = map.get("group");
//			BeanUtils.copyProperties(source, target);
                if(username != null || "".equals(username)){
                    infoMap.put("username",username);
                    infoMap.put("name",name);
                    infoMap.put("group",group);
                }
            }
            post.releaseConnection();
            return infoMap;
        }
        private void redirectStrategy(HttpServletRequest request, HttpServletResponse response,String userid) throws IOException {
            String redirectUrl = "http://localhost:8081/?loginType=3&userid="+userid;
            new DefaultRedirectStrategy().sendRedirect(request, response, redirectUrl);
        }
    }

    static class JAuthenticationToken extends AbstractAuthenticationToken {

        private Object principal;
        private HttpServletRequest request;

        public JAuthenticationToken(HttpServletRequest request) {
            super(Collections.emptyList());
            this.request = request;
        }
        public HttpServletRequest getRequest() {
            return request;
        }
        public JAuthenticationToken(Object principal, Collection<? extends GrantedAuthority> authorities) {
            super(authorities);
            this.principal = principal;
            setAuthenticated(true);
        }

        @Override
        public Object getCredentials() {
            return null;
        }

        @Override
        public Object getPrincipal() {
            return principal;
        }
    }
    static class JAuthenticationProvider implements AuthenticationProvider {

        private Authentication createSuccessAuthentication(HttpServletRequest request) {
            User user = new User("user", "123456", AuthorityUtils.createAuthorityList("USER"));
            JAuthenticationToken authenticationToken = new JAuthenticationToken(user, AuthorityUtils.createAuthorityList("USER"));
            AuthenticationDetailsSource<HttpServletRequest, ?> authenticationDetailsSource = new WebAuthenticationDetailsSource();
            authenticationToken.setDetails(authenticationDetailsSource.buildDetails(request));
            return authenticationToken;
        }
        @Override
        public Authentication authenticate(Authentication authentication) throws AuthenticationException {
            JAuthenticationToken authenticationToken = (JAuthenticationToken) authentication;
            return createSuccessAuthentication(authenticationToken.getRequest());
        }

        @Override
        public boolean supports(Class<?> authentication) {
            return JAuthenticationToken.class.isAssignableFrom(authentication);
        }
    }
}

